﻿using System;
using System.IO;
using System.Web.Routing;
using System.Web.Mvc;
using System.Linq;
using cludg.Domain.Content.Stories.Subjects;
using cludg.Infrastructure.Core;
using cludg.Services.Images;
using cludg.Web.Core;
using cludg.Web.Core.Utils;
using cludg.Web.Core.Validation;
using cludg.Services.Content;
using cludg.Web.Core.Controllers;
using cludg.Infrastructure.Core.Attributes;
using cludg.Web.Core.Security;
using cludg.Web.Core.ViewModels;
using cludg.Domain.Content.Stories;
using cludg.Web.ViewModels;
using cludg.Utils.Html;

namespace cludg.Web.Controllers
{
	public class OfferController : BaseController
	{
		[Dependency]
		public IStoryService StoryService { get; set; }
		[Dependency]
		public ICommentService CommentService { get; set; }
		[Dependency]
		public IOfferService OfferService { get; set; }

		#region Add
		[PermissionRequierd("AddOffer")]
		public ActionResult Add()
		{
			var model = CreateModel<OfferModel>();
			model.NavigationMenu.SetActiveItem("AddOffer");
			return View("Add", model);
		}

		[HttpPost]
		[PermissionRequierd("AddOffer")]
		[Core.Captcha.CaptchaValidator]
		public ActionResult Add(OfferModel model)
		{
			InitModel(model);
			model.NavigationMenu.SetActiveItem("AddOffer");

			bool imageSaveSuccess = true;

			if (ModelState.IsValid)
			{
				Stream imageStream = null;
				// 1. If defined image content URL - load it to repository
				string realSizeImageId = string.Empty;
				string subjectImageId = string.Empty;
				if (!string.IsNullOrEmpty(model.ImageContentUrl))
				{
					// TODO: Надо проверку на размер и формат картинки до того, как скачали её
					imageStream = RequestUtils.Download(model.ImageContentUrl);
				}
				else
				{
					// 2. Load selected image
					if (Request.Files.Count > 0)
					{
						var contentImageFile = Request.Files[model.ImageUploadFileName];
						if (contentImageFile != null && contentImageFile.InputStream != null && contentImageFile.ContentLength > 0)
						{
							// check for image size and type
							string validationMessage;
							if (!ImageValidationUtil.ValidatePostedImageFile(contentImageFile,
								ImageValidationUtil.SubjectImageSize, out validationMessage))
							{
								imageSaveSuccess = false;
								ModelState.AddModelError(string.Empty, validationMessage);
							}
							else
							{
								imageStream = contentImageFile.InputStream;
							}
						}
						else
						{
							// Не указан ни один источник для картинки
							imageSaveSuccess = false;
							ModelState.AddModelError(string.Empty, "Необходимо указать ссылку на изображение или выбрать изображение на вашем компьютере.");
						}
					}
				}
				if (imageSaveSuccess)
				{
					using (imageStream)
					{
						if (imageStream != null)
						{
							var ids = ImageService.Add(imageStream, new[] { ImageSize.Real, ImageSize.ImageSubject }, true);
							realSizeImageId = ids[0];
							subjectImageId = ids[1];
						}
					}

					OfferService.NewOffer(new ImageSubject { RealSizeImageId = realSizeImageId, SubjectImageId = subjectImageId },
										  GetCurrentUser(false), model.Comment, model.Title, model.AnonymouseAuthorName);
					ShowMessage(MessageType.Info, "Предложение добавлено");

					return RedirectToAction("Index", "Home");
				}
			}

			return View("Add", model);
		}

		#endregion

		#region Approve/Decline
		protected virtual TModel CreateOfferApprovingModel<TModel>(Offer offer) where TModel : OfferApprovingModel, new()
		{
			return CreateModel<TModel>(
				delegate(TModel model)
				{
					model.Offer = offer;
					model.Title = offer.Title;
					model.Body = offer.Comment;
					model.AnonymouseAuthorName = offer.AnonymouseAuthorName;
				}
			);
		}

		[PermissionRequierd("ApproveOffer")]
		public ActionResult Approve(string id)
		{
			var offer = OfferService.ById(id);
			if (offer == null)
				return RedirectToAction("List");

			var model = CreateOfferApprovingModel<OfferApprovingModel>(offer);

			return View(model);
		}

		[HttpPost]
		[ValidateInput(false)]
		[PermissionRequierd("ApproveOffer")]
		[PermissionRequierd("AddStory")]
		public ActionResult Approve(OfferApproveModel model)
		{
			InitModel(model);

			var offer = OfferService.ById(model.OfferId);
			if (offer == null)
				return RedirectToAction("List");

			if (!ModelState.IsValid)
			{
				var model2 = CreateModel<OfferApprovingModel>();
				model2.Offer = offer;
				model2.Title = model.Title;
				model2.Body = model.Body;
				model2.AnonymouseAuthorName = model.AnonymouseAuthorName;
				return View(model2);
			}

			var story = OfferService.Approve(
				offer, 
				GetCurrentUser(false), 
				model.Title,
				model.Body.HtmlSantinized(),
				model.AnonymouseAuthorName,
                model.Tags);

			ShowMessage(MessageType.Info, "Предложение одобрено");

			return RedirectToRoute("Story", new { name = story.UniqueName });
		}

		[PermissionRequierd("DeclineOffer")]
		public ActionResult Decline(string id)
		{
			var offer = OfferService.ById(id);
			if (offer == null)
				return RedirectToAction("List");

			OfferService.Decline(offer, GetCurrentUser());

			ShowMessage(MessageType.Info, "Предложение отклонено");

			return RedirectToAction("List");
		}
		#endregion

		#region List
		private void AddOfferListMenuItem(Web.Core.ViewModels.Menu menu, string caption, string actionName, bool selected)
		{
			var url = UrlHelper.GenerateUrl(null,
				actionName,
				"Offer",
				null,
				RouteTable.Routes,
				Request.RequestContext,
				true);
			menu.Items.Add(new MenuItem { Caption = caption, Url = url, Selected = selected });
		}

		protected OfferListModel CreateOfferListModel(Offer.OfferState offerState)
		{
			var model = CreateModel<OfferListModel>();

			model.OffersMenu = new Web.Core.ViewModels.Menu();
			AddOfferListMenuItem(model.OffersMenu, "Новые", "List", offerState == Offer.OfferState.Offered);
			AddOfferListMenuItem(model.OffersMenu, "Принятые", "ListApproved", offerState == Offer.OfferState.Approved);
			AddOfferListMenuItem(model.OffersMenu, "Отклоненные", "ListDeclined", offerState == Offer.OfferState.Declined);

			model.Offers = OfferService.All.Where(x => x.State == offerState);

			return model;
		}

		protected string GenerateUniqueFeedId()
		{
			return Guid.NewGuid().ToString().Replace("-", string.Empty).ToLowerInvariant();
		}

		[PermissionRequierd("ViewOffers")]
		public ActionResult List()
		{
			var model = CreateOfferListModel(Offer.OfferState.Offered);

			// Если у пользователья нет уникальной ссылки на поток новых предложений - создадим её.
			// Иначе просто получим
			var uniqueFeedId = SettingService[Const.SettingNewOffersUniqueFeedId, GetCurrentUserId()] as string;
			if (string.IsNullOrWhiteSpace(uniqueFeedId))
			{
				uniqueFeedId = GenerateUniqueFeedId();
				SettingService[Const.SettingNewOffersUniqueFeedId, GetCurrentUserId()] = uniqueFeedId;
			}
			model.UniqueFeedId = uniqueFeedId;

			model.NavigationMenu.SetActiveItem("Offers");
			return View("List", model);
		}

		[PermissionRequierd("ViewOffers")]
		public ActionResult ListApproved()
		{
			var model = CreateOfferListModel(Offer.OfferState.Approved);
			model.NavigationMenu.SetActiveItem("Offers");
			return View("List", model);
		}

		[PermissionRequierd("ViewOffers")]
		public ActionResult ListDeclined()
		{
			var model = CreateOfferListModel(Offer.OfferState.Declined);
			model.NavigationMenu.SetActiveItem("Offers");
			return View("List", model);
		}
		#endregion
	}
}
